﻿using Manon.Core.Extensions;
using Manon.Core.Jwt.Dto;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Text;

namespace Manon.Core.Jwt
{
    public class JwtAppService : IJwtAppService
    {

        /// <summary>
        /// 过期时间默认 1天  1*24*60
        /// </summary>
        private static int Expire = 1440;



        public JwtAuthorizationOutput GenerateAccessToken(JwtAuthorizationInput input)
        {
            Expire = input.Expire;

            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(input.SigningKey));
            var tokenHandler = new JwtSecurityTokenHandler();

            var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
            var token = new SecurityTokenDescriptor()
            {
                Issuer = input.Issuer,
                Audience = input.Audience,
                Claims = input.claims,
                Expires = DateTime.Now.AddMinutes(input.Expire),
                SigningCredentials = creds
            };

            var securityToken = tokenHandler.CreateToken(token);

            //存储 Token 信息
            var jwt = new JwtAuthorizationOutput
            {
                Expire = input.Expire,
                Token = tokenHandler.WriteToken(securityToken),
                RefreshToken = GenerateRefreshToken()
            };
            return jwt;
        }


        public string GenerateRefreshToken()
        {
            var randomNumber = new byte[32];
            using (var rng = RandomNumberGenerator.Create())
            {
                rng.GetBytes(randomNumber);
                return Convert.ToBase64String(randomNumber);
            }
        }

        public ClaimsPrincipal GetPrincipalFromExpiredToken(string token, string issuer, string audience, string signingKey)
        {
            var tokenValidationParameters = new TokenValidationParameters
            {
                ValidateAudience = false, //you might want to validate the audience and issuer depending on your use case
                ValidateIssuer = false,
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(signingKey)),
                ValidateLifetime = false
            };

            var tokenHandler = new JwtSecurityTokenHandler();
            SecurityToken securityToken;
            var principal = tokenHandler.ValidateToken(token, tokenValidationParameters, out securityToken);
            var jwtSecurityToken = securityToken as JwtSecurityToken;

            if (jwtSecurityToken == null || !jwtSecurityToken.Header.Alg.Equals(SecurityAlgorithms.HmacSha256, StringComparison.InvariantCultureIgnoreCase))
                throw new SecurityTokenException("Invalid token");

            return principal;
        }

        /// <summary>
        /// 刷新 Token
        /// </summary>
        /// <param name="token">Token</param>
        /// <param name="dto">用户信息</param>
        /// <returns></returns>
        public JwtAuthorizationOutput Refresh(string token, JwtAuthorizationInput input)
        {
            var principal = GetPrincipalFromExpiredToken(token, input.Issuer, input.Audience, input.SigningKey);


            var newJwtToken = GenerateAccessToken(input);

            return new JwtAuthorizationOutput()
            {
                Token = newJwtToken.Token,
                Expire = input.Expire,
                RefreshToken = newJwtToken.RefreshToken
            };
        }

    }
}
